// INCLUDES --------------------------------------------------------------------
#include "Color.h"

// FUNCTIONS -------------------------------------------------------------------

/* GENERAL:
   d    -> destination
   s    -> source
   size -> array size (0,1 for single elements)

   c    -> arbitrary color
   a,b  -> two arbitrary colors
   k    -> floating point scalar
*/

// clear to [r:0,g:0,b:0,a:1]
void ColorClear(ColorRGBA *c, ui32 size)
{
  GUARD_NULL("ColorClear *c", c);

  // clamp range to at least one element
  CLAMP_LOW(size, 1); 

  memset(c, 0, sizeof(ColorRGBA)*size);          // clear color to [0,0,0,0]
  
  i32 i;
  for (i = 0; i < (i32)size; i++) c[i].a = 1.0f; // set a=1
};

// clone color src->dest
void ColorCopy(ColorRGBA *d, ColorRGBA *s, ui32 size)
{
  // copy contents
  FillCopy(d, s, sizeof(ColorRGBA), size);
};

/* inverse color from a to -a. this is done by negating every component.
   thus we retrieve:

   -a = [-(r) -(g) -(b) -(a)]
*/
void ColorInvert(ColorRGBA *c) { ColorMulTo(c, -1.0f); };

// [+, +=] ---------------------------------------------------------------------
/* color addition:

   color addition is done by adding up each individual component of the color a
   with the corresponding component of the second color b.

   thus we retrieve:

   a + b = [ar+br ag+bg ab+bb aa+ba]

*/
void ColorAdd(ColorRGBA *d, ColorRGBA *a, ColorRGBA *b)
{
  GUARD_NULL("ColorAdd *d", d);
  GUARD_NULL("ColorAdd *a", a);
  GUARD_NULL("ColorAdd *b", b);

  d->r = a->r + b->r;
  d->g = a->g + b->g;
  d->b = a->b + b->b;
  d->a = a->a + b->a;
};

void ColorAddTo(ColorRGBA *d, ColorRGBA *a)
{
  GUARD_NULL("ColorAddTo *d", d);
  GUARD_NULL("ColorAddTo *a", a);

  d->r += a->r;
  d->g += a->g;
  d->b += a->b;
  d->a += a->a;
};

// [-, -=] ---------------------------------------------------------------------
/* color subtraction:

   color subtraction is done by subtracting each individual component
   of the second color b from the corresponding component of the first color a.

   thus we retrieve:

   a - b = [ar-br ag-bg ab-bb aa-ba]]
*/
void ColorSub(ColorRGBA *d, ColorRGBA *a, ColorRGBA *b)
{
  GUARD_NULL("ColorSub *d", d);
  GUARD_NULL("ColorSub *a", a);
  GUARD_NULL("ColorSub *b", b);

  d->r = a->r - b->r;
  d->g = a->g - b->g;
  d->b = a->b - b->b;
  d->a = a->a - b->a;
};

void ColorSubTo(ColorRGBA *d, ColorRGBA *a)
{
  GUARD_NULL("ColorSubTo *d", d);
  GUARD_NULL("ColorSubTo *a", a);

  d->r -= a->r;
  d->g -= a->g;
  d->b -= a->b;
  d->a -= a->a;
};

// [*, *=] ---------------------------------------------------------------------
/* color multiplication:

   color multiplication is done by multiplicating each individual component
   of the color a with the given scalar k.

   thus we retrieve:

   ka = [k*ax k*ay k*az]
*/
void ColorMul(ColorRGBA *d, ColorRGBA* a, fp k)
{
  GUARD_NULL("ColorMul *d", d);
  GUARD_NULL("ColorMul *a", a);

  d->r = a->r * k;
  d->g = a->g * k;
  d->b = a->b * k;
  d->a = a->a * k;
};

void ColorMulTo(ColorRGBA *d, fp k)
{
  GUARD_NULL("ColorMulTo *d", d);

  d->r *= k;
  d->g *= k;
  d->b *= k;
  d->a *= k;
};

// [/, /=] ---------------------------------------------------------------------
/* color division:

   color division is done by dividing each individual component
   of the color a with the given scalar k.

   thus we retrieve:

   a / k = [ax/k ay/k az/k]

   for performance and safety we convert the division into a multiplication.
*/
void ColorDiv(ColorRGBA *d, ColorRGBA* a, fp k)
{
  GUARD_ZERO("ColorDiv k", k);

  fp factor = 1.0f / k;
  ColorMul(d, a, factor);
};

void ColorDivTo(ColorRGBA *d, fp k)
{
  GUARD_ZERO("ColorDiv k", k);

  fp factor = 1.0f / k;
  ColorMulTo(d, factor);
};

// [==, !=] --------------------------------------------------------------------
/* vector equality

   two vectors a,b are equal if all their corresponding components are equal.

   thus we retrieve:

   a == b <-> (ax==bx, ay==by, az==bz)
*/
bool ColorEquals(ColorRGBA *a, ColorRGBA *b)
{
  GUARD_NULL("ColorEquals *a", a, false);
  GUARD_NULL("ColorEquals *b", b, false);

  // binary compare the two memory structures
  if (memcmp(a, b, sizeof(ColorRGBA)) == 0) return true;
  else return false;
};

bool ColorInEquals(ColorRGBA *a, ColorRGBA *b) { return !ColorEquals(a, b); };
